home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / archiver / pdtar.zip / CREATE.C < prev    next >
C/C++ Source or Header  |  1988-05-15  |  16KB  |  685 lines

  1. /*
  2.  * Create a tar archive.
  3.  *
  4.  * Written 25 Aug 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  5.  * MS-DOS port 2/87 by Eric Roskos.
  6.  * Minix  port 3/88 by Eric Roskos.
  7.  *
  8.  * @(#)create.c 1.19 9/9/86 Public Domain - gnu
  9.  */
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <fcntl.h>
  13. #include <stdio.h>
  14.  
  15. #ifndef MSDOS
  16. #include <pwd.h>
  17. #include <grp.h>
  18. #else                            /* ifdef MSDOS */
  19. #include <assert.h>
  20. #endif
  21.  
  22. #ifdef BSD42
  23. #include <sys/dir.h>
  24. #else
  25. /*
  26.  * FIXME: On other systems there is no standard place for the header file
  27.  * for the portable directory access routines.  Change the #include line
  28.  * below to bring it in from wherever it is.  Of course, where it is
  29.  * on BSD is the standard place ... :-)?
  30.  */
  31. #ifdef V7
  32. #include "dir.h"
  33. #else
  34. #include "ndir.h"
  35. #endif /* V7 */
  36. #endif /* !BSD42 */
  37.  
  38. #ifdef USG
  39. #ifdef MSDOS
  40. /* DOS doesn't have minor device numbers */
  41. #define major(n)    n
  42. #define minor(n)    0
  43. #else
  44. #include <sys/sysmacros.h>        /* major() and minor() defined here */
  45. #endif
  46. #endif
  47.  
  48. /*
  49.  * V7 doesn't have a #define for this.
  50.  */
  51. #ifndef O_RDONLY
  52. #define    O_RDONLY    0
  53. #endif
  54.  
  55. #include "tar.h"
  56.  
  57. /*
  58.  * If there are no symbolic links, there is no lstat().  Use stat().
  59.  */
  60. #ifndef S_IFLNK
  61. #define lstat stat
  62. #endif
  63.  
  64. extern char    *malloc();
  65. extern char    *strcpy();
  66. extern char    *strncpy();
  67. extern int      errno;
  68.  
  69. union record   *start_header();
  70. void            finish_header();
  71. void            finduname();
  72. void            findgname();
  73. char           *name_next();
  74. void            to_oct();
  75.  
  76.  
  77. void
  78. create_archive()
  79. {
  80.     register char  *p;
  81.  
  82.     open_archive(0);            /* Open for writing */
  83.  
  84.     while (p = name_next())
  85.     {
  86.         dump_file(p);
  87.     }
  88.  
  89.     write_eot();
  90.     close_archive();
  91.     name_close();
  92. }
  93.  
  94. #ifdef MSDOS
  95. /*
  96.  * count the number of bytes in file f.  This is done because, with DOS,
  97.  * the results of the stat call may not reflect the actual file size, due
  98.  * to conversion of CR/LF pairs to plain LF's.  The *only* way to find this
  99.  * out is to read the whole file in order to let the MSC library routines
  100.  * determine how many characters will actually be in the file...
  101.  */
  102. long
  103. countbytes(f)
  104. int             f;
  105. {
  106.     long            cb;
  107.     int             n;
  108.     char            buf[512];
  109.  
  110.     assert(lseek(f, 0L, 1) == 0L);
  111.  
  112.     for (cb = 0; (n = read(f, buf, sizeof(buf))) > 0;)
  113.         cb += n;
  114.     lseek(f, 0L, 0);
  115.  
  116.     assert(lseek(f, 0L, 1) == 0L);
  117.  
  118.     return (cb);
  119. }
  120.  
  121. #endif
  122.  
  123. /*
  124.  * Dump a single file.  If it's a directory, recurse.
  125.  * Result is 1 for success, 0 for failure.
  126.  */
  127. int
  128. dump_file(p)
  129. char           *p;                /* File name to dump */
  130. {
  131.     struct stat     statbuff[1];
  132.     struct stat    *statbuf = statbuff;    
  133.     union record   *header;
  134.     char            type;
  135.  
  136.     /*
  137.      * Use stat if following (rather than dumping) 4.2BSD's symbolic links. 
  138.      * Otherwise, use lstat (which, on non-4.2 systems, is #define'd to stat
  139.      * anyway. 
  140.      */
  141.     if (0 != f_follow_links ? stat(p, statbuf) : lstat(p, statbuf))
  142.     {
  143. badperror:
  144.         perror(p);
  145. badfile:
  146.         errors++;
  147.         return 0;
  148.     }
  149.  
  150.     switch (statbuf->st_mode & S_IFMT)
  151.     {
  152.  
  153.     case S_IFREG:                /* Regular file */
  154.         {
  155.             int             f;    /* File descriptor */
  156.             int             bufsize, count;
  157.             register long   sizeleft;
  158.             register union record *start;
  159.             long            exp, actl;    /* byte counts for file size errs */
  160.             int             nbytes, need;        /* for block read loop */
  161.             int             n;    /* # bytes read in this read() call */
  162.             char           *bufp;        /* where to start this read in buf */
  163.  
  164.             /*
  165.              * Handle a regular file with multiple links. 
  166.              *
  167.              * We maintain a list of all such files that we've written so far. 
  168.              * Any time we see another, we check the list and avoid dumping
  169.              * the data again if we've done it once already. 
  170.              */
  171.             if (statbuf->st_nlink > 1)
  172.             {
  173.                 register struct link *lp;
  174.  
  175.                 /*
  176.                  * First quick and dirty.  Hashing, etc later FIXME 
  177.                  */
  178.                 for (lp = linklist; lp; lp = lp->next)
  179.                 {
  180.                     if (lp->ino == statbuf->st_ino &&
  181.                         lp->dev == statbuf->st_dev)
  182.                     {
  183.                         /* We found a link. */
  184.                         statbuf->st_size = 0;
  185.                         header = start_header(p, statbuf);
  186.                         if (header == NULL)
  187.                             goto badfile;
  188.                         strcpy(header->header.linkname,
  189.                             lp->name);
  190.                         header->header.linkflag = LF_LINK;
  191.                         finish_header(header);
  192.                         if (f_verbose)
  193.                             annorec(stdout, (char *) NULL);
  194.                         printf("%s link to %s\n",
  195.                             p, lp->name);
  196.  
  197.                         /*
  198.                          * Maybe remove from list after all links found? 
  199.                          */
  200.  
  201.                         /*
  202.                          * If so, have to compare names in case he dumps
  203.                          * twice. 
  204.                          */
  205.  
  206.                         /*
  207.                          * Later: I don't understand the above.  If she dumps
  208.                          * the file twice, it would be BAD to dump it the
  209.                          * second time as a link... gnu 25Jul86 
  210.                          */
  211.                         /* FIXME */
  212.                         goto donefile;
  213.                     }
  214.                 }
  215.  
  216.                 /* Not found.  Add it to the list. */
  217.                 lp = (struct link *) malloc((unsigned)
  218.                     (strlen(p) + sizeof(struct link) - NAMSIZ));
  219.                 lp->ino = statbuf->st_ino;
  220.                 lp->dev = statbuf->st_dev;
  221.                 strcpy(lp->name, p);
  222.                 lp->next = linklist;
  223.                 linklist = lp;
  224.             }
  225.  
  226.             sizeleft = statbuf->st_size;
  227. #ifdef NOTDEF                    /* don't understand reason for following,
  228.                                  * causes abort */
  229.             /* Don't bother opening empty, world readable files. */
  230.             if (sizeleft > 0 || 0444 != (0444 & statbuf->st_mode))
  231.             {
  232. #endif
  233.                 f = open(p, O_RDONLY | convmode(p));
  234.                 if (f < 0)
  235.                     goto badperror;
  236. #ifdef NOTDEF
  237.             }
  238.             else
  239.             {
  240.                 f = -1;
  241.             }
  242. #endif
  243.  
  244. #ifdef MSDOS
  245.  
  246.             /*
  247.              * See comment before countbytes(), above. 
  248.              */
  249.             if (convmode(p) & O_TEXT)
  250.             {
  251.                 statbuf->st_size = countbytes(f);
  252.                 sizeleft = statbuf->st_size;
  253.             }
  254. #endif
  255.             exp = sizeleft;        /* number of bytes we expect to see */
  256.             actl = 0;            /* number of bytes we really saw */
  257.  
  258.             header = start_header(p, statbuf);
  259.             if (header == NULL)
  260.                 goto badfile;
  261.             finish_header(header);
  262.             while (sizeleft > 0)
  263.             {
  264.                 start = findrec();
  265.                 bufsize = endofrecs()->charptr - start->charptr;
  266.                 if (sizeleft < bufsize)
  267.                     bufsize = sizeleft;
  268.  
  269.                 /*
  270.                  * use a read loop since reads < number requested do NOT
  271.                  * imply EOF as John assumed -- jer 22Aug87 
  272.                  */
  273.                 need = bufsize;
  274.                 bufp = start->charptr;
  275.                 count = 0;
  276.                 do
  277.                 {
  278.                     n = read(f, bufp, need);
  279.                     if (n > 0)
  280.                     {
  281.                         count += n;
  282.                         bufp += n;
  283.                         need -= n;
  284.                     }
  285.                 } while (need > 0 && n > 0);
  286.  
  287.                 if (n < 0)
  288.                 {
  289.                     annorec(stderr, tar);
  290.                     fprintf(stderr,
  291.                         "read error at byte %ld, reading %d bytes, in file ",
  292.                         statbuf->st_size - sizeleft,
  293.                         bufsize);
  294.                     perror(p);    /* FIXME */
  295.                     goto padit;
  296.                 }
  297.  
  298.                 actl += count;
  299.                 sizeleft -= count;
  300.  
  301.                 userec(start + (count - 1) / RECORDSIZE);
  302.                 if (count == bufsize)
  303.                     continue;
  304.  
  305.                 annorec(stderr, tar);
  306.                 fprintf(stderr,
  307.                     "%s: file size error: expected %ld, read %ld.\n",
  308.                     p, exp, actl);
  309.                 fprintf(stderr,
  310.                     "%s: file shrunk by %d bytes, padding with zeros.\n",
  311.                     p, sizeleft);
  312.                 goto padit;        /* Short read */
  313.             }
  314.             if (f >= 0)
  315.                 (void) close(f);
  316.  
  317.             /* Clear last block garbage to zeros, FIXME */
  318.  
  319. #ifdef OLDVERBOSE
  320.             if (f_verbose)
  321.             {
  322.                 annorec(stdout, (char *) NULL);
  323.                 printf("%s\n", p);
  324.             }
  325. #endif
  326.     donefile:
  327.             break;
  328.  
  329.             /*
  330.              * File shrunk or gave error, pad out tape to match the size we
  331.              * specified in the header. ??? Doesn't do that here!  Must be a
  332.              * FIXME. -- jer 
  333.              */
  334.     padit:
  335.             abort();
  336.         }
  337.  
  338. #ifdef S_IFLNK
  339.     case S_IFLNK:                /* Symbolic link */
  340.         {
  341.             int             size;
  342.  
  343.             statbuf->st_size = 0;        /* Force 0 size on symlink */
  344.             header = start_header(p, statbuf);
  345.             if (header == NULL)
  346.                 goto badfile;
  347.             size = readlink(p, header->header.linkname, NAMSIZ);
  348.             if (size < 0)
  349.                 goto badperror;
  350.             if (size == NAMSIZ)
  351.             {
  352.                 annorec(stderr, tar);
  353.                 fprintf(stderr,
  354.                     "%s: symbolic link too long\n", p);
  355.                 break;
  356.             }
  357.             header->header.linkname[size] = '\0';
  358.             header->header.li